#include "stdafx.h"
#include "Sound.h"

#include "Log.h"
#include "Exception.h"

namespace Cvekas {

// TODO: error checking in pause/stop
// TODO: fix looping

SoundSample::SoundSample(const std::string &name, ResourceId id, const std::string &filename)
	: Sound(name, id, filename), last_channel(NULL), start_pos(-1.0f)
{
	LOG(FORMAT("Loading sound sample %s from file %s", % name % filename)); 

	// Support 8 max simultaneos playbacks
	handle = BASS_SampleLoad(false, filename.c_str(), 0, 0, 8, 0);

	if(!handle)
		throw EXCEPTION(FORMAT("Unable to load sound sample %s. BASS error code: %d",
			% name % BASS_ErrorGetCode()));
}

SoundSample::~SoundSample()
{
	LOG(FORMAT("Destroying sound sample %s", % name));

	if(!BASS_SampleFree(handle))
		throw EXCEPTION(FORMAT("Unable to destroy sound sample %s. BASS error code: %d",
			% name % BASS_ErrorGetCode()));
}

void SoundSample::play(bool loop)
{
	last_channel = BASS_SampleGetChannel(handle, false);
	
	if(start_pos > 0.0f)
	{
		setPosition(start_pos);
		start_pos = -1.0f;
	}

	BASS_ChannelPlay(last_channel, false);
}

void SoundSample::stop()
{
	if(!last_channel)
		return;

	BASS_ChannelStop(last_channel);
}

void SoundSample::pause()
{
	if(!last_channel)
		return;

	BASS_ChannelPause(last_channel);
}

float SoundSample::getLength()
{
	uint64 length = BASS_ChannelGetLength(handle, BASS_POS_BYTE);
	return (float)BASS_ChannelBytes2Seconds(handle, length);
}

float SoundSample::getPosition()
{
	if(!last_channel)
		return 0.0f;

	uint64 pos = BASS_ChannelGetPosition(last_channel, BASS_POS_BYTE);
	return (float)BASS_ChannelBytes2Seconds(handle, pos);
}

void SoundSample::setPosition(float t)
{
	if(!last_channel)
		start_pos = t;

	uint64 pos = BASS_ChannelSeconds2Bytes(handle, (double)t);
	BASS_ChannelSetPosition(last_channel, pos, BASS_POS_BYTE);
}


SoundStream::SoundStream(const std::string &name, ResourceId id, const std::string &filename)
	: Sound(name, id, filename)
{
	LOG(FORMAT("Loading sound stream %s from file %s", % name % filename)); 

	handle = BASS_StreamCreateFile(false, filename.c_str(), 0, 0, 0);
	if(!handle)
		throw EXCEPTION(FORMAT("Unable to load sound stream %s. BASS error code: %d",
			% name % BASS_ErrorGetCode()));
}

SoundStream::~SoundStream()
{
	stop();
	LOG(FORMAT("Destroying sound stream %s", % name));

	if(!BASS_StreamFree(handle))
		throw EXCEPTION(FORMAT("Unable to destroy sound stream %s. BASS error code: %d",
			% name % BASS_ErrorGetCode()));
}

void SoundStream::play(bool loop)
{
	BASS_ChannelPlay(handle, false);
}

void SoundStream::stop()
{
	BASS_ChannelStop(handle);
}

void SoundStream::pause()
{
	BASS_ChannelPause(handle);
}

float SoundStream::getLength()
{
	uint64 length = BASS_ChannelGetLength(handle, BASS_POS_BYTE);
	return (float)BASS_ChannelBytes2Seconds(handle, length);
}

float SoundStream::getPosition()
{
	uint64 pos = BASS_ChannelGetPosition(handle, BASS_POS_BYTE);
	return (float)BASS_ChannelBytes2Seconds(handle, pos);
}

void SoundStream::setPosition(float t)
{
	uint64 pos = BASS_ChannelSeconds2Bytes(handle, (double)t);
	BASS_ChannelSetPosition(handle, pos, BASS_POS_BYTE);
}

} // namespace
